package tcc.wa.service;

import java.io.IOException;
import java.util.Date;

import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import tcc.wa.model.CurrentWeatherCondition;
import tcc.wa.model.Location;
import tcc.wa.persistence.dao.CurrentWeatherConditionDAO;
import android.content.Context;
import android.util.Log;

/**
 * Service class for CurrentWeatherCondition.
 */
public class CurrentWeatherConditionService {
	
	private final String TAG = "CurrentWeatherConditionService";
	
	private final String updateCurrentWeatherConditionUrl = "http://api.wunderground.com/api/d09917472096c37e/conditions/forecast/q/{latitude},{longitude}.json";
	
	private final CurrentWeatherConditionDAO currentWeatherConditionDAO;
	
	public CurrentWeatherConditionService(Context context) {
		currentWeatherConditionDAO = new CurrentWeatherConditionDAO(context);
	}
	
	/**
	 * Updates the CurrentWeatherCondition.
	 *
	 * @param location the location
	 * @return the current weather condition
	 * @throws ClientProtocolException the client protocol exception
	 * @throws IOException Signals that an I/O exception has occurred
	 * @throws JSONException in case it fails to parse the response
	 */
	public CurrentWeatherCondition update(Location location) throws ClientProtocolException, IOException, JSONException {
		Log.i(TAG, "Updating current weather condition...");
		String requestString = updateCurrentWeatherConditionUrl.replace("{latitude}", String.valueOf(location.getGeographicCoordinate().getLatitude()));
		requestString = requestString.replace("{longitude}", String.valueOf(location.getGeographicCoordinate().getLongitude()));
		HttpClient httpClient = new DefaultHttpClient();
		HttpGet request = new HttpGet(requestString);
		ResponseHandler<String> handler = new BasicResponseHandler();
		String result = httpClient.execute(request, handler);
		httpClient.getConnectionManager().shutdown();
		JSONObject jsonObject = new JSONObject(result);
		JSONObject currentConditions = jsonObject.getJSONObject("current_observation");
		JSONArray forecasts = jsonObject.getJSONObject("forecast").getJSONObject("simpleforecast").getJSONArray("forecastday");
		CurrentWeatherCondition currentCondition = buildCurrentWeatherConditionFrom(currentConditions, forecasts, location);
		Log.i(TAG, "Succesfully obtained new weather condition.");
		return currentCondition;
	}
	
	/**
	 * Saves a CurrentWeatherCondition.
	 *
	 * @param condition the condition to be saved
	 */
	public void save(CurrentWeatherCondition condition) {
		Log.i(TAG, "Saving current weather condition...");
		currentWeatherConditionDAO.save(condition);
		Log.i(TAG, "Successfully saved current weather condition.");
	}
	
	/**
	 * Finds the last saved CurrentWeatherCondition.
	 *
	 * @return the last saved current weather condition
	 */
	public CurrentWeatherCondition findLast() {
		Log.i(TAG, "Finding last current weather condition...");
		CurrentWeatherCondition currentCondition = currentWeatherConditionDAO.findLast();
		if (currentCondition != null)
			Log.i(TAG, "Found last current weather condition.");
		else
			Log.i(TAG, "Couldn't find last current weather condition.");
		return currentCondition;
	}
	
	/**
	 * Builds the current weather condition from the web service response.
	 *
	 * @param currentConditions a JSONObject containing the raw CurrentWeatherConditions
	 * @param forecasts a JSONObject containing the raw Forecasts
	 * @param location the device location
	 * @return the current weather condition
	 * @throws JSONException in case it fails to parse the response
	 */
	private CurrentWeatherCondition buildCurrentWeatherConditionFrom(JSONObject currentConditions, JSONArray forecasts, Location location) throws JSONException {
		JSONObject forecast = getForecastForCurrentDay(forecasts);
		double currentTemperature = currentConditions.getDouble("temp_c");
		double currentPrecipitation = currentConditions.getDouble("precip_1hr_metric");
		String relativeHumidityString = currentConditions.getString("relative_humidity");
		double currentRelativeHumidity = Double.parseDouble(relativeHumidityString.substring(0, relativeHumidityString.indexOf("%")));
		double maximumTemperature = forecast.getJSONObject("high").getDouble("celsius");
		double minimumTemperature = forecast.getJSONObject("low").getDouble("celsius");
		CurrentWeatherCondition currentWeatherCondition = new CurrentWeatherCondition();
		currentWeatherCondition.setCurrentTemperature(currentTemperature);
		currentWeatherCondition.setCurrentPrecipitation(currentPrecipitation);
		currentWeatherCondition.setCurrentRelativeHumidity(currentRelativeHumidity);
		currentWeatherCondition.setDate(new Date());
		currentWeatherCondition.setLocation(location);
		currentWeatherCondition.setMaximumTemperature(maximumTemperature);
		currentWeatherCondition.setMinimumTemperature(minimumTemperature);
		return currentWeatherCondition;
	}
	
	/**
	 * Gets the forecast for current day.
	 *
	 * @param forecasts a JSONObject containing the raw Forecasts
	 * @return the forecast for current day
	 * @throws JSONException in case it fails to parse the response
	 */
	private JSONObject getForecastForCurrentDay(JSONArray forecasts) throws JSONException{
		JSONObject forecast = null;
		int currentIndex = 0;
		while (currentIndex < forecasts.length() && forecast == null) {
			JSONObject currentForecast = forecasts.getJSONObject(currentIndex);
			if (currentForecast.getInt("period") == 1)
				forecast = currentForecast;
			currentIndex++;
		}
		return forecast;
	}
}
